/*
 * CTerrain.cpp
 *
 *  Created on: Oct 4, 2011
 *      Author: welcome
 */

#include "CTerrain.h"

using namespace GGEngine;

CTerrain::CTerrain(gg2D* agg2D) {
	xzscale = 1.0f;
	this->agg2D = agg2D;
	aAllocator = gg2D_getAllocator(agg2D);
	textureMapAvailable = GL_FALSE;
	detailTextureAvailable = GL_FALSE;
	heightMap = KD_NULL;
	localVertices = KD_NULL;
	vertexIndices = KD_NULL;
	texCoord = 0;
	gg2DRawImage landTexture;

	gg2DRawImage_initialize(&landTexture);
	gg2DAllocator * aAllocator = gg2D_getAllocator(agg2D);
	gg2DRawImage_loadJPEG(&landTexture, aAllocator, "/data/green.jpg");

	// generate the land texture as a mipmap
	glGenTextures(1, &textureMapName);
	glBindTexture(GL_TEXTURE_2D, textureMapName);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, landTexture.m_width,
			landTexture.m_height, 0, GL_RGB, GL_UNSIGNED_BYTE,
			landTexture.m_buffer);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

	textureMapAvailable = GL_TRUE;
}

CTerrain::~CTerrain() {

	resetHeightMap();

	position[0] = 0.0f;
	position[1] = 0.0f;
	position[2] = 0.0f;
}
GLvoid CTerrain::resetHeightMap() {

	if (heightMap) {
		gg2DRawImage_release(heightMap, aAllocator);
		kdFree(heightMap);
		heightMap = KD_NULL;
	}
	if (localVertices) {
		delete[] localVertices;

		localVertices = 0;
	}

	if (vertexIndices) {
		delete[] vertexIndices;

		vertexIndices = 0;
	}
	if (texCoord)
	{
		delete[] texCoord;

		texCoord = 0;
	}
	xzscale = 1.0f;

	heightMapWidth = 0;

	heightMapAvailable = GL_FALSE;
}
KDint CTerrain::loadHeightMap(const char * const fileName, GLfloat xzstep,
		GLfloat ystep) {

	resetHeightMap();

	if (!fileName) {
		return -1;
	}
	heightMap = (gg2DRawImage*) kdMalloc(sizeof(gg2DRawImage));

	gg2DRawImage_initialize(heightMap);

	if (gg2DRawImage_loadTGA(heightMap, aAllocator, fileName) != GG2D_NO_ERROR) {
		return -1;
	} else {
		if (heightMap->m_width == heightMap->m_height && heightMap->m_width
				>= 2) {

			GLuint x = 0;
			GLuint z = 0;

			heightMapWidth = heightMap->m_width;

			xzscale = xzstep;

			localVertices = new GLfloat[3 * heightMapWidth * heightMapWidth];

			if (localVertices == 0) {
				resetHeightMap();
				return -1;
			}

			vertexIndices = new GLushort[heightMapWidth * 2 * (heightMapWidth
					- 1)];

			if (vertexIndices == 0) {
				resetHeightMap();
				return -1;
			}

			GLubyte* buffer = (GLubyte*) heightMap->m_buffer;

			for (z = 0; z < heightMapWidth; z++) {
				for (x = 0; x < heightMapWidth; x++) {
					localVertices[(x + z * heightMapWidth) * 3] = (GLfloat) x
							* xzstep;
					localVertices[(x + z * heightMapWidth) * 3 + 1]
							= (GLfloat) buffer[x + (heightMapWidth - 1 - z)
									* heightMapWidth] * ystep;
					localVertices[(x + z * heightMapWidth) * 3 + 2]
							= (GLfloat) z * xzstep;
				}
			}
			for (z = 0; z < heightMapWidth - 1; z++) {
				for (x = 0; x < heightMapWidth; x++) {
					if (z % 2 == 0) {
						vertexIndices[(x + z * heightMapWidth) * 2] = z
								* heightMapWidth + x;
						vertexIndices[(x + z * heightMapWidth) * 2 + 1] = (z
								+ 1) * heightMapWidth + x;
					} else {
						vertexIndices[(x + z * heightMapWidth) * 2] = (z + 1)
								* heightMapWidth + heightMapWidth - 1 - x;
						vertexIndices[(x + z * heightMapWidth) * 2 + 1] = z
								* heightMapWidth + heightMapWidth - 1 - x;
					}
				}
			}
		} else {
			resetHeightMap();
			return -1;
		}
	}
	heightMapAvailable = GL_TRUE;

	texCoord = new GLfloat[2 * heightMapWidth * heightMapWidth];

	if (texCoord == 0)
	{
		resetHeightMap();
	}
	for (GLuint z = 0; z < heightMapWidth; z++) {
		for (GLuint x = 0; x < heightMapWidth; x++) {
			texCoord[(x + z * heightMapWidth) * 2] = (GLfloat) x
					/ (heightMapWidth - 1);
			texCoord[(x + z * heightMapWidth) * 2 + 1]
					= (GLfloat) (heightMapWidth - 1 - z) / (heightMapWidth - 1);
		}
	}
	return 0;
}
void CTerrain::render() {

	glPushMatrix();

	glTranslatef(position[0], position[1], position[2]);

	if (heightMapAvailable) {

		glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

		glEnableClientState(GL_VERTEX_ARRAY);

		glVertexPointer(3, GL_FLOAT, 0, localVertices);

		if (textureMapAvailable) {

			glEnableClientState(GL_TEXTURE_COORD_ARRAY);

			glTexCoordPointer(2, GL_FLOAT, 0, texCoord);

			glEnable(GL_TEXTURE_2D);

			glBindTexture(GL_TEXTURE_2D, textureMapName);

		}

		if (detailTextureAvailable) {
			glClientActiveTexture(GL_TEXTURE1);

			glEnableClientState(GL_TEXTURE_COORD_ARRAY);

			glTexCoordPointer(2, GL_FLOAT, 0, detailTexCoord);

			glActiveTexture(GL_TEXTURE1);

			glEnable(GL_TEXTURE_2D);

			glBindTexture(GL_TEXTURE_2D, detailTextureName);

			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
		}

		glDrawElements(GL_TRIANGLE_STRIP, (heightMapWidth - 1) * heightMapWidth
				* 2, GL_UNSIGNED_SHORT, vertexIndices);

		glDisableClientState(GL_VERTEX_ARRAY);

		if (detailTextureAvailable) {
			glDisableClientState(GL_TEXTURE_COORD_ARRAY);

			glDisable(GL_TEXTURE_2D);

			glClientActiveTexture(GL_TEXTURE0);

			glActiveTexture(GL_TEXTURE0);
		}

		if (textureMapAvailable) {

			glDisableClientState(GL_TEXTURE_COORD_ARRAY);

			glDisable(GL_TEXTURE_2D);
		}
	}

	glPopMatrix();
}

